# 
# Project: Last.sk
# File: lastsk.py
# Author: Angel Luis Calvo Ortega
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


#this import statement allows access to the karamba functions
import karamba

import xml.sax
import os
import ConfigParser

import profile
from views import *

from dataworker import DataWorker
from profileworker import ProfileWorker
from avatarworker import AvatarWorker

# kdialog command which shows select skin menu
skinCmd = ['kdialog', '--radiolist', 'Select a skin:', '0', 'Pink', '', '1',
           'Black', '', '2', 'Blue', '', '--title', 'Select skin', '--caption', 'Last.sk']

# Views
VIEWS = (topartists.TopArtistsHandler(), 
         topalbums.TopAlbumsHandler(),
         toptracks.TopTracksHandler(),
         toptags.TopTagsHandler(),
         friends.FriendsHandler(),
         neighbours.NeighboursHandler(),
         recenttracks.RecentTracksHandler(),
         weeklyartistchart.WeeklyArtistChartHandler(),
         weeklyalbumchart.WeeklyAlbumChartHandler(),
         weeklytrackchart.WeeklyTrackChartHandler(),
         systemrecs.SystemRecsHandler())


# Shows a view
def repaint(widget, dText, uText, newAvatar):
    global dataText, profileText, avatarImage, lastskPath
    if dText != None:
        karamba.changeRichText(widget, dataText, dText)
        karamba.setRichTextWidth(widget, dataText, 256)
    if uText != None:
        karamba.changeRichText(widget, profileText, uText)
        karamba.setRichTextWidth(widget, profileText, 192)
    if newAvatar:
        karamba.setImagePath(widget, avatarImage, os.path.join(lastskPath, 'avatar.png'))
        karamba.resizeImage(widget, avatarImage, 64, 64)
    if dText != None or uText != None or newAvatar:
        karamba.redrawWidget(widget)


def setView(widget):
    global viewIndex, user, dataWorker
    dataWorker = DataWorker(VIEWS[viewIndex], user)
    dataWorker.start()


# Retrieves and shows user's profile
def setUser(widget):
    global user, profileWorker
    profileWorker = ProfileWorker(user)
    profileWorker.start()


# Gets new user's profile
def changeUser(widget):
    global user, userBox
    newUser = karamba.getInputBoxValue(widget, userBox)
    if newUser != user:
        user = newUser
        setUser(widget)
        clearCaches()
        writeConfig()


# Clears all cached data of views
def clearCaches():
    for view in VIEWS:
        view.clear()


# Clear cached data of actual view
def clearCache():
    global viewIndex
    VIEWS[viewIndex].clear()


# Reads config file
def readConfig():
    global user, viewIndex, skin, lastskPath
    config = ConfigParser.RawConfigParser()
    config.read(os.path.join(lastskPath, 'lastsk.conf'))
    user = ''
    viewIndex = 0
    skin = '0'
    if config.has_section('global'):
        if config.has_option('global', 'user'):
            user = config.get('global', 'user')
        if config.has_option('global', 'viewIndex'):
            viewIndex = config.getint('global', 'viewIndex')
        if config.has_option('global', 'skin'):
            skin = config.get('global', 'skin')


# Writes state to file
def writeConfig():
    global user, viewIndex, skin, lastskPath
    config = ConfigParser.RawConfigParser()
    config.add_section('global')
    config.set('global', 'user', user)
    config.set('global', 'viewIndex', viewIndex)
    config.set('global', 'skin', skin)
    f = file(os.path.join(lastskPath, 'lastsk.conf'), 'w')
    config.write(f)
    f.close()


# Changes the skin
def changeSkin(widget):
    global skin, bgImage, userBox
    karamba.setImagePath(widget, bgImage, 'images/bg%s.png' % skin)
    if skin == '0':
        karamba.changeInputBoxBackgroundColor(widget, userBox, 0xb8, 0x24, 0x42)
    elif skin == '1':
        karamba.changeInputBoxBackgroundColor(widget, userBox, 0x28, 0x28, 0x28)
    else:
        karamba.changeInputBoxBackgroundColor(widget, userBox, 0x11, 0x45, 0xA5)
    karamba.redrawWidgetBackground(widget)


#this is called when you widget is initialized
def initWidget(widget):
    global profileText, dataText, avatarImage, userBox
    global leftButton, rightButton, setUserButton, popUpMenu, listButton, refreshButton
    global viewIndex, user, lastskPath, viewsMenu, bgImage, updatesCount
    global dataWorker, profileWorker, avatarWorker
    
    # Creates theme path
    lastskPath = os.path.join(os.environ['HOME'], '.superkaramba/lastsk')
    if not os.path.exists(lastskPath):
        os.mkdir(lastskPath)

    # Reads config
    readConfig()

    dataWorker = None
    profileWorker = None
    avatarWorker = None
    if user != None and user != '':
        setUser(widget)
        setView(widget)
    
    # User input box
    userBox = karamba.createInputBox(widget, 2, 34, 128, 24, user)
    karamba.changeInputBoxFontSize(widget, userBox, 14)
    karamba.changeInputBoxFontColor(widget, userBox, 0xC8, 0xC8, 0xC8)
    
    # Set skin
    bgImage = karamba.createBackgroundImage(widget, 0, 0, '')
    changeSkin(widget)
    
    # Set user button
    setUserButton = karamba.createImage(widget, 132, 34, 'images/apply.png')
    karamba.attachClickArea(widget, setUserButton, '', '', '')
    karamba.addImageTooltip(widget, setUserButton, 'Set user')
    # Profile text
    profileText = karamba.createRichText(widget, 'Loading...', False)
    karamba.moveRichText(widget, profileText, 0, 54)
    # Avatar image
    avatarImage = karamba.createImage(widget, 190, 34, '')
    # View text
    dataText = karamba.createRichText(widget, 'Loading...', False)
    karamba.moveRichText(widget, dataText, 0, 100)
    # Left arrow button
    leftButton = karamba.createImage(widget, 184, 102, 'images/leftarrow.png')
    karamba.attachClickArea(widget, leftButton, '', '', '')
    karamba.addImageTooltip(widget, leftButton, 'Previous view')
    # Right arrow button
    rightButton = karamba.createImage(widget, 202, 102, 'images/rightarrow.png')
    karamba.attachClickArea(widget, rightButton, '', '', '')
    karamba.addImageTooltip(widget, rightButton, 'Next view')
    # Views list button
    listButton = karamba.createImage(widget, 220, 102, 'images/bottom.png')
    karamba.attachClickArea(widget, listButton, '', '', '')
    karamba.addImageTooltip(widget, listButton, 'Views list')
    # Refresh view button
    refreshButton = karamba.createImage(widget, 238, 102, 'images/reload.png')
    karamba.attachClickArea(widget, refreshButton, '', '', '')
    karamba.addImageTooltip(widget, refreshButton, 'Refresh view')

    # Views list popup menu
    viewsMenu = []
    popUpMenu = karamba.createMenu(widget)
    for view in VIEWS:
        viewsMenu.append(karamba.addMenuItem(widget, popUpMenu, view.title, ''))
 
    # About menu item
    karamba.addMenuConfigOption(widget, 'skin', 'Select skin')
    karamba.setMenuConfigOption(widget, 'skin', 0)
    # Menu separator
    karamba.addMenuConfigOption(widget, 'about', 'About...')
    karamba.setMenuConfigOption(widget, 'about', 0)

    updatesCount = 0

#This is called when your widget is closed.  You can use this to clean
#up open files, etc.  You don't need to delete text and images in your
#theme.  That is done automatically.  This callback is just for cleaning up
#external things.  Most people don't need to put anything here.
def widgetClosed(widget):
    writeConfig()


#this is called everytime your widget is updated
#the update inverval is specified in the .theme file
def widgetUpdated(widget):
    global dataWorker, profileWorker, avatarWorker, user, lastskPath, updatesCount
    # Limpia la cache cada 5 mins
    #updatesCount += 1
    #if updatesCount > 150:
    #    clearCache()
    #    updatesCount = 0

    newProfile = None
    if profileWorker != None and profileWorker.finished:
        newProfile = profileWorker.results
        if avatarWorker == None or avatarWorker.finished:
            avatarWorker = AvatarWorker(profileWorker.handler.avatar, os.path.join(lastskPath, 'avatar.png'))
            avatarWorker.start()
        profileWorker = None
    newAvatar = False
    if avatarWorker != None and avatarWorker.finished:
        newAvatar = avatarWorker.results
        avatarWorker = None
    newData = None
    if dataWorker != None and dataWorker.finished:
        newData = dataWorker.results
        dataWorker = None
    repaint(widget, newData, newProfile, newAvatar)


#This gets called everytime our widget is clicked.
#Notes:
#  widget = reference to our widget
#  x = x position (relative to our widget)
#  y = y position (relative to our widget)
#  botton = button clicked:
#                    1 = Left Mouse Button
#                    2 = Middle Mouse Button
#                    3 = Right Mouse Button, but this will never happen
#                        because the right mouse button brings up the
#                        Karamba menu.
#                    4,5 = Scroll wheel up and down
def widgetClicked(widget, x, y, button):
    pass


#This gets called everytime our widget is clicked.
#Notes
#  widget = reference to our widget
#  x = x position (relative to our widget)
#  y = y position (relative to our widget)
#  botton = button being held:
#                    0 = No Mouse Button
#                    1 = Left Mouse Button
#                    2 = Middle Mouse Button
#                    3 = Right Mouse Button, but this will never happen
#                        because the right mouse button brings up the
#                        Karamba menu.
def widgetMouseMoved(widget, x, y, button):
    #Warning:  Don't do anything too intensive here
    #You don't want to run some complex piece of code everytime the mouse moves
    pass


#This gets called when an item is clicked in a popup menu you have created.
#  menu = a reference to the menu
#  id = the number of the item that was clicked.
def menuItemClicked(widget, menu, id):
    global viewIndex, viewsMenu
    for i in range(len(viewsMenu)):
        if viewsMenu[i] == id:
            viewIndex = i
            setView(widget)
            break


#This gets called when an item is clicked in the theme CONFIGURATION menu,
#not the popup menus that you create.
#  key = the reference to the configuration key that was changed
#  value = the new value (true or false) that was selected
def menuOptionChanged(widget, key, value):
    if key == 'about':
        karamba.setMenuConfigOption(widget, 'about', 0)
        karamba.execute('kdialog --msgbox "<h2>Last.sk 0.3</h2>Angel Luis Calvo Ortega<br>Pollo Verde Software 2007" --title "About" --caption "Last.sk"')
    elif key == 'skin':
        global skinPid, skin
        karamba.setMenuConfigOption(widget, 'skin', 0)
        skinCmd[5] = 'on'
        skinCmd[8] = 'off'
        skinCmd[11] = 'off'
        if skin == '1':
            skinCmd[5] = 'off'
            skinCmd[8] = 'on'
        elif skin == '2':
            skinCmd[5] = 'off'
            skinCmd[11] = 'on'
        skinPid = karamba.executeInteractive(widget, skinCmd)


#This gets called when a meter (image, text, etc) is clicked.
# NOTE you must use attachClickArea() to make a meter
# clickable.  
#  widget = reference to your theme
#  meter = the meter clicked
#  button = the button clicked (see widgetClicked for button numbers)
def meterClicked(widget, meter, button):
    global leftButton, rightButton, setUserButton, listButton, viewIndex
    if button == 1:
        if meter == leftButton:
            viewIndex -= 1
            if viewIndex == -1:
                viewIndex = len(VIEWS) - 1
            setView(widget)
        elif meter == rightButton:
            viewIndex = (viewIndex + 1) % len(VIEWS)
            setView(widget)
        elif meter == setUserButton:
            changeUser(widget)
            setView(widget)
        elif meter == listButton:
            global popUpMenu
            karamba.popupMenu(widget, popUpMenu, 220, 118)
        elif meter == refreshButton:
            clearCache()
            setView(widget)


#This gets called when a command you have executed with executeInteractive() outputs something
#to stdout.  This way you can get the output of for example kdialog without freezing up the widget
#waiting for kdialog to end.
#  widget = reference to your theme
#  pid = process number of the program outputting (use this if you execute more than out process)
#  output = the text the program outputted to stdout
def commandOutput(widget, pid, output):
    global skinPid
    if skinPid == pid:
        global skin
        newSkin = output.strip()
        if (newSkin == '0' or newSkin == '1' or newSkin == '2') and skin != newSkin:
            skin = newSkin
            changeSkin(widget)
        skinPid = None


#This gets called when an item is dropped on this widget.
# NOTE you have to call acceptDrops() before your widget will accept drops.
#  widget = reference to your theme
#  dropText = the text of the dropped item (probably a URL to it's location in KDE)
def itemDropped(widget, dropText):
    pass


#This gets called when a new program is LOADING in KDE.  When it is done
#loading, startupRemoved() is called, followed by taskAdded().
#  widget = reference to your widget
#  task = A refence to the task that is starting.  
def startupAdded(widget, startup):
    pass


#This gets called when a new program is done LOADING in KDE.
#  widget = reference to your widget
#  task = A refence to the task that just finished loading.  
def startupRemoved(widget, startup):
    pass


#This is called every time a new task (program) is started in KDE.
#  widget = reference to your widget
#  task = A refence to the new task.  Call getTaskInfo() with this reference
#         to get the name, etc of this new task.
def taskAdded(widget, task):
    pass


#This is called everytime a task (program) is closed in KDE.
#  widget = reference to your widget
#  task = A refence to the task.  
def taskRemoved(widget, task):
    pass


#This is called everytime a different task gains focus (IE, the user clicks
#on a different window).  
#  widget = reference to your widget
#  task = A refence to the task.  Call getTaskInfo() with this reference
#         to get the name, etc of this new task.
def activeTaskChanged(widget, task):
    pass

#This is called everytime the systray you created with createSystray() is updated
def systrayUpdated(widget):
    pass

#This is called everytime the current desktop changes
#  widget = reference to your widget
#  desktop = the current desktop
def desktopChanged(widget, desktop):
    pass

#This is called everytime the wallpaper changes on a desktop 
#  widget = reference to your widget
#  desktop = the desktop whose wallpaper changed
def wallpaperChanged(widget, desktop):
    pass

#This is called everytime there is a key press in any focused input field
#  widget = reference to your widget
#  meter = reference to an input box
#  char = the key that was pressed
def keyPressed(widget, meter, char):
    pass

# This will be printed when the widget loads.
print "Last.sk Loaded!"

